using MediatR;
using Dapper;
using System.Linq;
using RBAC.Domain.PurchasingManagement.PurchaseOrders;
using RBAC.ErrorCode;
using RBAC.Interstructrue.Base;
using RBAC.Write.Api.Application.Command.ERP.PurchasingManagement.PurchaseOrders;

namespace RBAC.Write.Api.Application.Handler.ERP.PurchasingManagement.PurchaseOrders
{
    public class AddPurchaseOrderCommandHandler : IRequestHandler<AddPurchaseOrderCommand, APIResult<int>>
    {
        private readonly IBaseRepository<PurchaseOrderInfo> _purchaseOrderRepo;
        private readonly ILogger<AddPurchaseOrderCommandHandler> _logger;
        private readonly IDbConnectionFactory _connectionFactory;

        public AddPurchaseOrderCommandHandler(IBaseRepository<PurchaseOrderInfo> purchaseOrderRepo,
            ILogger<AddPurchaseOrderCommandHandler> logger,
            IDbConnectionFactory connectionFactory)
        {
            _purchaseOrderRepo = purchaseOrderRepo;
            _logger = logger;
            _connectionFactory = connectionFactory;
        }

        public async Task<APIResult<int>> Handle(AddPurchaseOrderCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 基本校验
                if (string.IsNullOrWhiteSpace(request.DocCode))
                    return new APIResult<int> { Code = APIEnums.Fail, Msg = "单据编码不能为空", Data = 0 };
                if (string.IsNullOrWhiteSpace(request.supplierId))
                    return new APIResult<int> { Code = APIEnums.Fail, Msg = "供应商ID不能为空", Data = 0 };

                // 唯一性校验（按单据编码）
                var exists = _purchaseOrderRepo.GetFirstOrDefault("DocCode = @DocCode", new { request.DocCode });
                if (exists != null)
                    return new APIResult<int> { Code = APIEnums.Fail, Msg = "单据编码已存在", Data = 0 };

                // 映射命令到实体（仅映射实体存在的字段）
                var entity = new PurchaseOrderInfo
                {
                    DocCode = request.DocCode,
                    BizType = request.BizType,
                    Operatorer = request.Operatorer,
                    supplierId = request.supplierId,
                    docDate = request.docDate,
                    docType = request.docType,
                    arrivalDate = request.arrivalDate,
                    docStatus = request.docStatus,
                    purchaseDept = request.purchaseDept,
                    auditDate = request.auditDate,
                    contractUpload = request.contractUpload,
                    bizStatus = request.bizStatus,
                    purchaser = request.purchaser,
                    materialDemand = request.materialDemand,
                    contractNo = request.contractNo,
                    remark = request.remark,
                       
                    // BaseEntity 默认值: CreateTime/CreateUser/IsDeleted 在构造时已给默认
                };

                // 持久化主表（Dapper）
                var newId = _purchaseOrderRepo.Create(entity);

                // 同步新增到 PurchasingMaterialInfo（多明细）
                if (newId > 0 && request.Details != null && request.Details.Any())
                {
                    try
                    {
                        using var conn = _connectionFactory.CreateConnectionWithRetry();
                        using var tran = conn.BeginTransaction();

                        var sql = @"INSERT INTO PurchasingMaterialInfo
                            (PurchaseOrderId, DocumentaryNumber, PlannedOrderNumber, materialCode, materialName, modelSpec, mainUnit,
                             demandDate, qty, unitPrice, amount, arrivalQty, PurchasingInstructions, IsDel)
                            VALUES
                            (@PurchaseOrderId, @DocumentaryNumber, @PlannedOrderNumber, @materialCode, @materialName, @modelSpec, @mainUnit,
                             @demandDate, @qty, @unitPrice, @amount, @arrivalQty, @PurchasingInstructions, @IsDel);";

                        foreach (var d in request.Details)
                        {
                            var parameters = new
                            {
                                PurchaseOrderId = (long)newId,
                                DocumentaryNumber = d.DocumentaryNumber,
                                PlannedOrderNumber = d.PlannedOrderNumber,
                                materialCode = d.materialCode,
                                materialName = d.materialName,
                                modelSpec = d.modelSpec,
                                mainUnit = d.mainUnit,
                                demandDate = d.demandDate,
                                qty = d.qty,
                                unitPrice = d.unitPrice,
                                amount = (d.amount.HasValue && d.amount.Value > 0) ? d.amount.Value : d.unitPrice * d.qty,
                                arrivalQty = d.arrivalQty,
                                PurchasingInstructions = d.PurchasingInstructions,
                                IsDel = false
                            };

                            var cmd = new CommandDefinition(sql, parameters, transaction: tran, commandTimeout: 60);
                            conn.Execute(cmd);
                        }

                        tran.Commit();
                    }
                    catch (Exception ex)
                    {
                        _logger?.LogError(ex, "新增采购订单明细(PurchasingMaterialInfo，多条)失败: {Message}", ex.Message);
                        // 业务决定：明细失败不回滚主表。如需强一致，可抛出异常并在上层使用分布式/本地事务包裹主/子插入。
                    }
                }

                return new APIResult<int>
                {
                    Code = newId > 0 ? APIEnums.Success : APIEnums.Fail,
                    Msg = newId > 0 ? "新增采购订单成功" : "新增采购订单失败",
                    Data = newId
                };
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "新增采购订单失败: {Message}", ex.Message);
                return new APIResult<int>
                {
                    Code = APIEnums.Fail,
                    Msg = "新增采购订单异常: " + ex.Message,
                    Data = 0
                };
            }
        }
    }
}
